home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’97 / Jasik Park - The Lost UI / JasikAppearance / JasikAppearance.cpp < prev    next >
Text File  |  1997-06-28  |  14KB  |  571 lines

  1. // JasikLookHack - ©1997 by Marc Sherman
  2.  
  3. #include "Types.h"
  4. #include "QuickDraw.h"
  5. #include "Windows.h"
  6. #include "Memory.h"
  7. #include "Resources.h"
  8. #include "OSUtils.h"
  9. #include "LowMem.h"
  10. #include "Files.h"
  11.  
  12. #include "SetupA4.h"
  13. #include "A4Stuff.h"
  14.  
  15. #define ASSERT(cond) do{if(!cond) DebugStr("\p" #cond);}while(false)
  16. #define VERIFY(cond) do{if(!cond) DebugStr("\p" #cond);}while(false)
  17. #define OS_VERIFY(func) do{OSErr err = (func); ASSERT(err == noErr);}while(false)
  18.  
  19. // The icon for the init to load
  20. const short kIconFamilyID = -834;
  21. const long kUpdateTicks = 60;
  22. const short kTaskMenuID = -834;
  23.  
  24. // Type definitions for trap patches
  25. typedef pascal void (*InsertMenuProcPtr)(MenuRef theMenu, short beforeID);
  26. typedef pascal void (*SystemTaskProcPtr)(void);
  27. typedef pascal Handle (*GetResourceProcPtr)(ResType rType, short rID);
  28. typedef pascal void (*SetMenuItemTextProcPtr)(MenuRef theMenu, short item, ConstStr255Param itemString);
  29. typedef pascal long (*MenuSelectProcPtr)(Point startPt);
  30.  
  31. // Global variables for original trap addresses
  32. InsertMenuProcPtr        gOldInsertMenu;
  33. SystemTaskProcPtr        gOldSystemTask;
  34. GetResourceProcPtr        gOldGetResource;
  35. SetMenuItemTextProcPtr    gOldSetMenuItemText;
  36. MenuSelectProcPtr        gOldMenuSelect;
  37.  
  38. static short gMyRefNum = 0;
  39.  
  40. //---------------------------------------------------------------------------
  41. // Compare two pascal strings
  42. //---------------------------------------------------------------------------
  43.  
  44. static Boolean PStrEqu(const StringPtr a, const StringPtr b)
  45. {
  46.     if(*a == *b)
  47.     {
  48.         for(int i = *a; i > 0; i--)
  49.         {
  50.             if(a[i] != b[i])
  51.             {
  52.                 return false;
  53.             }
  54.         }
  55.         return true;
  56.     }
  57.     return false;    
  58. }
  59.  
  60.  
  61. //---------------------------------------------------------------------------
  62. // Is this the Finder?
  63. //---------------------------------------------------------------------------
  64.  
  65. static Boolean IsFinder()
  66. {
  67.     // Bail if we're in the system still - curapname probably isn't init'ed
  68.     if(LMGetCurApRefNum() == 0)
  69.         return true;
  70.         
  71.     const StringPtr curApp = LMGetCurApName();
  72.     const StringPtr finderName = "\pFinder";
  73.     return PStrEqu(curApp, finderName);
  74. }
  75.  
  76. //---------------------------------------------------------------------------
  77. // RetitleAppleMenu to the memory size (using unofficially documented menu list structs)
  78. //---------------------------------------------------------------------------
  79.  
  80. struct MenuRec
  81. {
  82.     MenuHandle menuOH;
  83.     short menuLeft;
  84. };
  85.  
  86. struct DynamicMenuList
  87. {
  88.     short lastMenu;
  89.     short lastRight;
  90.     short mbResID;
  91.     MenuRec menu[1];
  92. };
  93.  
  94. static void SetMenuTitle(MenuHandle hMenu, StringPtr newTitle)
  95. {
  96.     // Bail if the new title equals the old title
  97.     if(PStrEqu(newTitle, hMenu[0]->menuData))
  98.         return;
  99.     
  100.     // Calculate the current length of the title text
  101.     int oldTitleLength = hMenu[0]->menuData[0];
  102.     int newTitleLength = newTitle[0];
  103.  
  104.     // Calc the new size of the handle
  105.     int oldHandleSize = GetHandleSize((Handle)hMenu);
  106.     int newHandleSize = oldHandleSize - oldTitleLength + newTitleLength;
  107.     
  108.     // Calc the positions of the item defs
  109.     Ptr oldItemDefPos = (Ptr)(hMenu[0]->menuData) + oldTitleLength + 1;
  110.     
  111.     // Buffer the item defs (in case we're shrinking the handle size)
  112.     int bufferSize = oldHandleSize - (oldItemDefPos - (Ptr)(*hMenu));
  113.     Ptr defBuffer = NewPtr(bufferSize);
  114.     BlockMoveData(oldItemDefPos, defBuffer, bufferSize);
  115.     
  116.     // Resize the handle
  117.     SetHandleSize((Handle)hMenu, newHandleSize);
  118.     
  119.     // Modify the menu name
  120.     BlockMoveData(newTitle, hMenu[0]->menuData, newTitleLength + 1);
  121.     
  122.     // Copy the buffered item defs from the buffer
  123.     Ptr newItemDefPos = (Ptr)(hMenu[0]->menuData) + newTitleLength + 1;
  124.     BlockMoveData(defBuffer, newItemDefPos, bufferSize);
  125.     
  126.     // Free the buffer
  127.     DisposePtr(defBuffer);
  128.     
  129.     // Draw the new menu bar next time through the event loop
  130.     InvalMenuBar();
  131. }
  132.  
  133. static void RetitleAppleMenu()
  134. {
  135.     static long callCount = 0;
  136.  
  137.     // Get the apple (first) menu
  138.     DynamicMenuList** hMbar = (DynamicMenuList**)LMGetMenuList();
  139.     ASSERT(hMbar);
  140.     ASSERT(*hMbar);
  141.     
  142.     // Only fiddle if there's a menu in the list
  143.     if(hMbar[0]->lastMenu)
  144.     {
  145.         MenuHandle hAppleMenu = hMbar[0]->menu[0].menuOH;
  146.         ASSERT(hAppleMenu);
  147.         ASSERT(*hAppleMenu);
  148.  
  149.         // Init the new title        
  150.         Str255 newTitle = "\pfreeK  ";
  151.  
  152.         if(callCount++ >= 20)
  153.         {
  154.             long freeK = 0;
  155.             
  156.             // Get the amount of memory free in the app or temp heap
  157.             if(IsFinder())            
  158.                 freeK = TempFreeMem() / 1024;
  159.             else
  160.                 freeK = FreeMem() / 1024;
  161.             
  162.             // Get the new title
  163.             NumToString(freeK, newTitle);
  164.             newTitle[++newTitle[0]] = 'K';
  165.         }
  166.         
  167.         SetMenuTitle(hAppleMenu, newTitle);
  168.     }
  169. }
  170.  
  171. inline char LowerChar(char c)
  172. {
  173.     if(c >= 'A' && c <= 'Z')
  174.         return c - 'A' + 'a';
  175.     else
  176.         return c;
  177. }
  178.  
  179. inline char UpperChar(char c)
  180. {
  181.     if(c >= 'a' && c <= 'z')
  182.         return c - 'a' + 'A';
  183.     else
  184.         return c;
  185. }
  186.  
  187. inline char IsVowel(char c)
  188. {
  189.     switch(LowerChar(c))
  190.     {
  191.         case 'a':
  192.         case 'e':
  193.         case 'i':
  194.         case 'o':
  195.         case 'u':
  196.             return true;
  197.     }
  198.     return false;
  199. }
  200.  
  201. static void RandomMenuItemStyle(MenuHandle hMenu, short item)
  202. {
  203.     Str255 theString;
  204.     GetMenuItemText(hMenu, item, theString);
  205.     
  206.     // Bail if the string is 0-length 
  207.     if(theString[0] == 0)
  208.         return;
  209.             
  210.     // hash the string text in lower case
  211.     unsigned long strHash = 0;
  212.     for(int i = 1; i <= theString[0]; i++)
  213.         strHash += LowerChar(theString[i]);
  214.     
  215.     switch(strHash % 10)
  216.     {
  217.         case 0:
  218.             // don't touch the capitalization
  219.             break;
  220.             
  221.         case 1:
  222.         case 2:
  223.         case 3:
  224.         case 4:
  225.             // lowercase the first letter
  226.             theString[1] = LowerChar(theString[1]);
  227.             break;
  228.             
  229.         case 5:
  230.             // remove some vowels
  231.             int newLen = 0;
  232.             int spaces = 0;
  233.             for(int srcChar = 1; srcChar <= theString[0]; srcChar++)
  234.             {
  235.                 if(theString[srcChar] == ' ')
  236.                     spaces++;
  237.                     
  238.                 if((spaces % 2) || !IsVowel(theString[srcChar]))
  239.                     theString[++newLen] = theString[srcChar];
  240.             }
  241.             theString[0] = newLen;
  242.             break;
  243.         
  244.         case 6:
  245.             // capitalize the menu
  246.             for(int i = 1; i <= theString[0]; i++)
  247.             {
  248.                 theString[i] = UpperChar(theString[i]);
  249.             }
  250.             break;
  251.             
  252.         case 7:
  253.         case 8:
  254.         case 9:
  255.             // Bold the menu
  256.             SetItemStyle(hMenu, item, bold);
  257.             break;
  258.     }
  259.     
  260.     (*gOldSetMenuItemText)(hMenu, item, theString);
  261. }
  262.  
  263. static void RandomMenuStyle(MenuHandle hMenu)
  264. {
  265.     short itemCount = CountMItems(hMenu);
  266.     for(int i = 1; i <= itemCount; i++)
  267.     {
  268.         RandomMenuItemStyle(hMenu, i);
  269.     }
  270. }    
  271.  
  272. //---------------------------------------------------------------------------
  273. // The patch functions
  274. //---------------------------------------------------------------------------
  275. static pascal void MyInsertMenu(MenuRef theMenu, short beforeID)
  276. {
  277.     // Set up A4 globals
  278.     EnterCallback();
  279.     
  280.     // First check to see if we have a task menu yet
  281.     if(!GetMenuHandle(kTaskMenuID))
  282.     {    
  283.         Str255 menuTitle = "\p0 - ROM / System";
  284.         
  285.         if(!IsFinder())
  286.         {
  287.             // Replace the menu title with a fake task number and app name
  288.             static int fakeTaskNum = 1;
  289.             NumToString(fakeTaskNum++, menuTitle);
  290.             menuTitle[++menuTitle[0]] = ' ';
  291.             menuTitle[++menuTitle[0]] = '-';
  292.             menuTitle[++menuTitle[0]] = ' ';
  293.             BlockMoveData(LMGetCurApName() + 1, menuTitle + menuTitle[0] + 1, LMGetCurApName()[0]);
  294.             menuTitle[0] += LMGetCurApName()[0];
  295.         }
  296.         
  297.         MenuHandle hTaskMenu = NewMenu(kTaskMenuID, menuTitle);
  298.         int i = 1;
  299.         InsertMenuItem(hTaskMenu, "\p(Class Tree Of …", i++);
  300.         InsertMenuItem(hTaskMenu, "\p(Objects by Time", i++);
  301.         InsertMenuItem(hTaskMenu, "\p(Objects by Class", i++);
  302.         InsertMenuItem(hTaskMenu, "\p(Objects of …", i++);
  303.         InsertMenuItem(hTaskMenu, "\p(Methods of …/Ω", i++);
  304.         InsertMenuItem(hTaskMenu, "\p(-", i++);
  305.         InsertMenuItem(hTaskMenu, "\p(Break on Ref to Class …", i++);
  306.         InsertMenuItem(hTaskMenu, "\p(-", i++);
  307.         InsertMenuItem(hTaskMenu, "\p(option-Click for WindowList", i++);
  308.  
  309.  
  310.         // Use the unpatched insert menu to add this menu
  311.         (*gOldInsertMenu)(hTaskMenu, 0);
  312.     }
  313.     
  314.     // If the title is Special, change it
  315.     if(PStrEqu(theMenu[0]->menuData, "\pSpecial"))
  316.         SetMenuTitle(theMenu, "\pSadoMasochism");
  317.         
  318.     // If we're adding to the end, add it before the task menu
  319.     if(beforeID == 0)
  320.         beforeID = kTaskMenuID;
  321.         
  322.     // Fiddle with the menu capitalization
  323.     RandomMenuStyle(theMenu);
  324.     
  325.     // Call the original routine
  326.     (*gOldInsertMenu)(theMenu, beforeID);
  327.     
  328.     // Retitle the Apple Menu
  329.     RetitleAppleMenu();
  330.  
  331.     // Tear down A4 globals
  332.     ExitCallback();
  333. }
  334.  
  335. static pascal void MySystemTask(void)
  336. {
  337.     // Set up A4 globals
  338.     EnterCallback();
  339.     
  340.     // Retitle the apple menu every few ticks
  341.     static long lastTick = 0;
  342.     if((TickCount() - lastTick) >= kUpdateTicks)
  343.     {
  344.         lastTick = TickCount();
  345.         RetitleAppleMenu();
  346.     }
  347.  
  348.     // Call the original routine
  349.     (*gOldSystemTask)();
  350.     
  351.     // Tear down A4 globals
  352.     ExitCallback();
  353. }
  354.  
  355. static Handle GetResourceFromMyFile ( ResType rType, short rID )
  356. {
  357.     short    refNum = CurResFile();
  358.     Handle    theHandle;
  359.     
  360.     UseResFile ( gMyRefNum );
  361.     theHandle = Get1Resource ( rType, rID );
  362.     UseResFile ( refNum );
  363.     return theHandle;
  364. }
  365.  
  366. static pascal Handle MyGetResource(ResType rType, short rID)
  367. {
  368.     // Set up A4 globals
  369.     EnterCallback();
  370.     
  371.     unsigned char    oldRomMapInsert = LMGetROMMapInsert();
  372.     unsigned char    oldTmpResLoad = LMGetTmpResLoad();
  373.     Handle        hResult = NULL;
  374.     Boolean        done = false;
  375.     
  376.     switch ( rType )
  377.     {
  378.         // Load our mctb 0 for green menus and WDEF 0 for window locking
  379.         case 'mctb':
  380.         case 'WDEF':
  381.             if( rID == 0 )
  382.             {
  383.                 hResult = GetResourceFromMyFile(rType, rID);
  384.                 if(hResult)
  385.                     done = true;
  386.             }
  387.             break;
  388.         
  389.         // ppat 16 should load our simple grey pattern
  390.         case 'ppat':
  391.             if( rID == 16 )
  392.             {
  393.                 hResult = GetResourceFromMyFile(rType, rID);
  394.                 if(hResult)
  395.                     done = true;
  396.             }
  397.             break;
  398.             
  399.     }
  400.     
  401.     if ( !done ) {
  402.         LMSetROMMapInsert(oldRomMapInsert);
  403.         LMSetTmpResLoad(oldTmpResLoad);
  404.         hResult = (*gOldGetResource)(rType, rID);
  405.     }
  406.  
  407.     // Tear down A4 globals
  408.     ExitCallback();
  409.  
  410.     return hResult;
  411. }
  412.  
  413. static pascal void MySetMenuItemText(MenuRef theMenu, short item, ConstStr255Param itemString)
  414. {
  415.     // Set up A4 globals
  416.     EnterCallback();
  417.     
  418.     // Call the original routine
  419.     (*gOldSetMenuItemText)(theMenu, item, itemString);
  420.     
  421.     // Update the random adornments
  422.     RandomMenuItemStyle(theMenu, item);
  423.     
  424.     // Tear down A4 globals
  425.     ExitCallback();
  426. }
  427.  
  428. static pascal long MyMenuSelect(Point startPt)
  429. {
  430.     // Set up A4 globals
  431.     EnterCallback();
  432.     
  433.     // Call the original routine
  434.     long result = (*gOldMenuSelect)(startPt);
  435.     
  436.     if(result == 0)
  437.     {
  438.         // Check if we were in disabled task menu
  439.         if((MenuChoice() & 0xFFFF0000) == (-834 << 16))
  440.         {
  441.             Alert(-834, NULL);
  442.         }
  443.     }
  444.     
  445.     // Tear down A4 globals
  446.     ExitCallback();
  447.     
  448.     return result;
  449. }
  450.  
  451.  
  452.  
  453. //---------------------------------------------------------------------------
  454. // KeepMeAround keeps the resource fork open - taken from Aaron © 1995 Gregory D. Landweber.
  455. //---------------------------------------------------------------------------
  456. // 680x0 code only
  457.  
  458. /* Code to keep an INIT file opened at boot time around all the time, à la
  459.    SuitCase II et al. */
  460.  
  461. typedef struct _res_map res_map;
  462. typedef struct _res_map *res_map_ptr;
  463. typedef struct _res_map **res_map_handle;
  464.  
  465. struct _res_map {
  466.     long                void1;        /* Reserved */
  467.     long                void2;        /* Reserved */
  468.     long                void3;        /* Reserved */
  469.     long                void4;        /* Reserved */
  470.     res_map_handle    next_map;    /* Handle of next resource map */
  471.     short            refNum;        /* fRefNum for this file */
  472.     short            fileAttrs;        /* Resource file attributes for this file */
  473.     short            tlOffset;        /* Type List Offset from beginning of map */
  474.     short            nlOffset;        /* Name List Offset from beginning of map */
  475. };
  476.  
  477. static void KeepMeAround ( short refNum )
  478. {
  479.     THz                saved_zone;
  480.     res_map_handle    map_copy;
  481.     res_map_handle    the_map;
  482.  
  483.     the_map = (res_map_handle)LMGetTopMapHndl();
  484.     
  485.     if ( (*the_map)->refNum == refNum ) {
  486.         map_copy = the_map;
  487.         LMSetTopMapHndl ( (Handle) (*the_map)->next_map );
  488.     }
  489.     else {
  490.         map_copy = (*the_map)->next_map;
  491.         while ( (*map_copy)->refNum != refNum ) {
  492.             the_map  = map_copy;
  493.             map_copy = (*the_map)->next_map;
  494.         }
  495.         (*the_map)->next_map = (*map_copy)->next_map;
  496.         the_map  = map_copy;
  497.     }
  498.  
  499.     saved_zone = GetZone();
  500.     SetZone ( LMGetSysZone() );
  501.     HandToHand ( (Handle *)&map_copy );
  502.     SetZone(saved_zone);
  503.     
  504.     DisposeHandle((Handle)the_map);
  505.  
  506.     the_map = (res_map_handle)LMGetSysMapHndl();
  507.     while ( (*the_map)->next_map )
  508.         the_map = (*the_map)->next_map;
  509.     (*the_map)->next_map  = map_copy;
  510.     (*map_copy)->next_map = nil;
  511. }
  512.  
  513. //---------------------------------------------------------------------------
  514. // The INIT main and patch installer.
  515. //---------------------------------------------------------------------------
  516.  
  517. // Undocumented calls that ensure that a resource file opened will not be closed
  518. pascal OSErr TurnSystemModeOn(void) = {0x3F3c, 0x0040, 0xa88f};
  519. pascal OSErr TurnSystemModeOff(void) = {0x3F3c, 0x0041, 0xa88f};
  520.  
  521. int main(void)
  522. {
  523.     EnterCodeResource();    // Set up for globals    
  524.     PrepareCallback();
  525.     
  526.     short refNum = CurResFile();
  527.     
  528.     Handle hShowInit = Get1Resource('Code', 7000);
  529.     if (hShowInit)
  530.         ((pascal void (*) (short, Boolean)) *hShowInit) (kIconFamilyID, true);
  531.     ReleaseResource(hShowInit);
  532.         
  533.     // Set up the patch - the INIT *must* be in the Sysheap
  534.     Handle hInit0 = Get1Resource('INIT',0);
  535.     if (hInit0) 
  536.     {
  537.         // Detach and lock the patch
  538.         DetachResource(hInit0);
  539.         HLock(hInit0);
  540.         HNoPurge(hInit0);
  541.  
  542.         // Get the old address
  543.         gOldInsertMenu = (InsertMenuProcPtr)NGetTrapAddress(_InsertMenu, ToolTrap);
  544.         gOldSystemTask = (SystemTaskProcPtr)NGetTrapAddress(_SystemTask, ToolTrap);
  545.         gOldGetResource = (GetResourceProcPtr)NGetTrapAddress(_GetResource, ToolTrap);
  546.         gOldSetMenuItemText = (SetMenuItemTextProcPtr)NGetTrapAddress(_SetMenuItemText, ToolTrap);
  547.         gOldMenuSelect = (MenuSelectProcPtr)NGetTrapAddress(_MenuSelect, ToolTrap);
  548.                 
  549.         // Install the patch
  550.         NSetTrapAddress((UniversalProcPtr)&MyInsertMenu, _InsertMenu, ToolTrap);
  551.         NSetTrapAddress((UniversalProcPtr)&MySystemTask, _SystemTask, ToolTrap);
  552.         NSetTrapAddress((UniversalProcPtr)&MyGetResource, _GetResource, ToolTrap);
  553.         NSetTrapAddress((UniversalProcPtr)&MySetMenuItemText, _SetMenuItemText, ToolTrap);
  554.         NSetTrapAddress((UniversalProcPtr)&MyMenuSelect, _MenuSelect, ToolTrap);
  555.     }
  556.     
  557.     // Find our resource file
  558.     FCBPBRec parms;
  559.     parms.ioFCBIndx = 0;
  560.     parms.ioRefNum = refNum;
  561.     OS_VERIFY(PBGetFCBInfoSync(&parms));
  562.     
  563.     gMyRefNum = HOpenResFile(parms.ioVRefNum, parms.ioFCBParID, parms.ioNamePtr, fsRdPerm);
  564.     OS_VERIFY(ResError());
  565.     
  566.     KeepMeAround(gMyRefNum);        
  567.  
  568.     ExitCodeResource();        // Shutdown use of globals (A4).
  569.  
  570.     return 0;
  571. }